#include "BondDealMatrixBlockBase.h"
#include "BondDealMatrixImpl.h"
#include "../StringResource.h"
#include <bondlib/BondContainer.h>
// #include <bondlib/BondDeal/PanoramicBondDealContainer.h>
#include <bondlib/BondDeal/PanoramicDataCenter.h>
#include <core/StyleMgr.h>
#include <core/time/time.h>
#include <qbtools/tools.h>
#include <uam/ServerTimeMgr.h>
#include <QMouseEvent>
#include <include/CmdDefines.h>
#include <qbbond/QbBondModule.h>
#include <uam/UserAccountManager.h>

namespace {
#define DOUBLE_INVALID -1e7
#define DOUBLE_ZERO 1e-6
#define CHECK_DOUBLE_VALID(v) v > DOUBLE_INVALID + 1e-5

	const int minTipsWidth = 160;

	const int levelCount = 5;
	const double levelIntrest[levelCount] = { 0.0, 0.5, 1.0, 2.0, 5.0 }; //信用债5个等级
	const double levelCredit[levelCount] = { 0, 2, 10, 50, 100 };//利率债5个等级
	const double levelNCD[levelCount] = { 0, 0.5, 1, 3, 10 };//NCD5个等级

	const int flashPosMax = 20;
	const QColor crNormal = 0x0B4D52;
	const QColor crCover = 0x744C21;
	const QColor crGreen[levelCount] = { crNormal, 0x152B25, 0x143529, 0x114732, 0x15643F };
	const QColor crRed[levelCount] = { crNormal, 0x222523, 0x332723, 0x512B26, 0x7F3129 };
}

BondDealMatrixBlockBase::BondDealMatrixBlockBase(BondDealMatrixImpl* p) : QWidget(p)
{
	m_parent = p;

	m_lfTitle = m_lfPrice = m_lfDiff = m_lfOperator = font();
	m_lfPrice.setPixelSize(16);
	m_lfPrice.setBold(true);
	m_lfDiff.setPixelSize(11);
	m_lfOperator.setPixelSize(8);
	m_lfOperator.setBold(true);

	m_flashTimer = new QTimer();
	m_flashTimer->callOnTimeout(this, &BondDealMatrixBlockBase::onTimeOut);

	setMouseTracking(true);
}

void BondDealMatrixBlockBase::showCell(bool bShow)
{
	m_show = bShow;
	if (m_show)show();
	else hide();
}

void BondDealMatrixBlockBase::updateCell(int bondIndex, bool needFlash)
{
	m_flashPos = 0;
	m_flashTimer->stop();
	if (bondIndex == -999 && needFlash)
	{//格子内容不刷新，仅闪烁
		m_flashPos = flashPosMax;
		m_flashTimer->start(2000 / flashPosMax);
		return;
	}
	m_bondIndex = bondIndex;
	updateString();
	if (!CBondContainer::instance().IsValidIndex(m_bondIndex))
	{
		hide();
		return;
	}
	if (!m_show)return;
	show();
	repaint();
	if (needFlash)
	{
		m_flashPos = flashPosMax;
		m_flashTimer->start(2000 / flashPosMax);
	}
}

void BondDealMatrixBlockBase::updateString()
{
	SCOPED_LOCK(CPanoramicDataCenter::instance()->GetLock(true));
	CPanoramicBondDealMap& dealMap = CPanoramicDataCenter::instance()->GetDealMap(true);

// 	CPanoramicBondDealContainer& bdc = CPanoramicBondDealContainer::instance();
// 	SCOPED_LOCK(bdc.GetLock());
	const BondDealInfo& pDealInfo = dealMap.getDealInfo(m_bondIndex); 
	auto itTrade = pDealInfo.m_tradeList.begin();

	bool isCDCGap = m_parent ? m_parent->isDiffCDC() : true;
	m_gapBP = DOUBLE_INVALID;
	m_strPrice.clear();
	m_strDiff = "--";
	if (itTrade != pDealInfo.m_tradeList.end())
	{
		if (isCDCGap && CHECK_DOUBLE_VALID(itTrade->m_cdcGapBP))m_gapBP = itTrade->m_cdcGapBP;
		else if (!isCDCGap && CHECK_DOUBLE_VALID(itTrade->m_closeGapBP))m_gapBP = itTrade->m_closeGapBP;
		m_strPrice = QString::fromLocal8Bit(itTrade->m_yield);
		m_strPrice = SSTools::PriceRemoveZero(m_strPrice, 2);
		if (CHECK_DOUBLE_VALID(m_gapBP))
		{
			if(m_gapBP > 1e-5)
				m_strDiff = QString::asprintf("+%.02f", m_gapBP);
			else 
				m_strDiff = QString::asprintf("%.02f", m_gapBP);
			m_strDiff = SSTools::PriceRemoveZero(m_strDiff, 0);
			m_strDiff.append("bp");
		}
	}
	if (m_strPrice.isEmpty())m_strPrice = "--";

	const CBondInfo& bi = CBondContainer::instance().ElementAtR(m_bondIndex);
	QString strTitleTemp;
	if (bi.is_interest_bond())
	{
		strTitleTemp = m_strTitle = QString::fromLocal8Bit(bi.GetCombBondCode());
	}
	else
	{
		strTitleTemp = QString::fromLocal8Bit(bi.GetBondShortName());
		char sName[256];
		FIELDCOPY(sName, bi.GetBondShortName());
		int len = strlen(sName);
		for (int n = len - 1; n >= 2; n--)
		{
			if ((sName[n] >= '0' && sName[n] <= '9') ||
				(sName[n] >= 'a' && sName[n] <= 'z') ||
				(sName[n] >= 'A' && sName[n] <= 'Z'))
				sName[n] = 0;
		}
		m_strTitle = QString::fromLocal8Bit(sName);
	}

	updateTipsString(strTitleTemp);
	QFontMetrics fmTitle(m_lfTitle);
	if (fmTitle.width(m_strTitle) > rect().width() - 4)
	{
		m_strTitle = fmTitle.elidedText(m_strTitle, Qt::ElideRight, rect().width() - 4);
	}
}

void BondDealMatrixBlockBase::updateTipsString(QString& strTitle)
{
	m_strTips.clear();
	m_vctTipsCustomItem.clear();
	if (!CBondContainer::instance().IsValidIndex(m_bondIndex))return;

	const CBondInfo& bi = CBondContainer::instance().ElementAtR(m_bondIndex);
	//title + ttm
	QString strLine = strTitle;
	strLine.append("    ");
	QString strTTM = QString::fromLocal8Bit(bi.GetRemainPeriod(ServerTimeMgr::instance().serverTime()));
	QFontMetrics fmTitle(m_lfTitle);
	QString strTemp = strLine + strTTM;
	while (fmTitle.width(strTemp) < minTipsWidth)
	{
		strLine.append(" ");
		strTemp = strLine + strTTM;
	}
	strLine.append(strTTM);
	m_strTips.append(strLine);
	m_strTips.append("\n");

	auto& dealInfo = CPanoramicBondDealContainer::instance().getDealInfo(m_bondIndex);
	//中债估值
	strLine = NewStringTable::strBondDealTips(0);
	strLine.append(" ");
	if(dealInfo.m_cdcValue > -1e7 + 1)
		strLine.append(QString::asprintf("%.04f", dealInfo.m_cdcValue));
	else
		strLine.append("--");
	strLine.append("\n");
	m_strTips.append(strLine);
	qb::QBTipCustomItem item;
	QColor crPrice = StyleMgr::instance().color("Highlight");
	item.clrNormal = crPrice;
	item.row = 1;
	item.col = 1;
	m_vctTipsCustomItem.push_back(item);

	//昨日收盘
	strLine = NewStringTable::strBondDealTips(1);
	strLine.append(" ");
	if (dealInfo.m_lastClose[0] != '\0')
	{
		QString strLastClose = QString::fromLocal8Bit(dealInfo.m_lastClose);
// 		double flastClose = atof(dealInfo.m_lastClose);
// 		QString strLastClose = QString::asprintf("%.04f", flastClose);
// 		strLastClose = SSTools::PriceRemoveZero(strLastClose, 2);
		strLine.append(strLastClose);
	}
	else
		strLine.append("--");

	bool bShowDetail = (strcmp(SSUserAccountManager::instance().GetGlobleVariabl(SSUserAccountManager::UseNewDealSource), "1") != 0
		|| (strcmp(SSUserAccountManager::instance().GetGlobleVariabl(SSUserAccountManager::UseNewDealSource), "1") == 0
			&& strcmp(SSUserAccountManager::instance().GetGlobleVariabl(SSUserAccountManager::ShowNewDealDetail), "1") == 0));

	if (bShowDetail)
		strLine.append("\n");
	m_strTips.append(strLine);
	item.clrNormal = crPrice;
	item.row = 2;
	item.col = 1;
	m_vctTipsCustomItem.push_back(item);

	if (!bShowDetail)return;

	int no = 0;
	QColor crTKN = StyleMgr::instance().color("Deal_TKN");
	QColor crGVN = StyleMgr::instance().color("Deal_GVN");
	QColor crTRD = StyleMgr::instance().color("Deal_TRD");
	for (auto& itTrade : dealInfo.m_tradeList)
	{
		tm tUpdate = qb::base::time2tm(itTrade.m_updateTime);
		strLine = QString::asprintf("%02d:%02d:%02d", tUpdate.tm_hour, tUpdate.tm_min, tUpdate.tm_sec);

		QString sPrice = QString::fromLocal8Bit(itTrade.m_price);
		sPrice = SSTools::PriceRemoveZero(sPrice, 2);
		strLine.append(" ").append(sPrice);
		
		QString sOperate;
		int nType = atoi(itTrade.m_operate);
		switch (nType) {
		case 0: sOperate = "TKN"; item.clrNormal = crTKN; break;
		case 1: sOperate = "GVN"; item.clrNormal = crGVN; break;
		case 2: sOperate = "TRD"; item.clrNormal = crTRD; break;
		default:sOperate = ""; break;
		}
		strLine.append(" ").append(sOperate).append("\n");
		m_strTips.append(strLine);
		item.row = 3 + no;
		item.col = 2;
		item.font = &m_lfOperator;
		m_vctTipsCustomItem.push_back(item);
		
		no++;
		if (no >= 3)break;
	}

	//今日共成交
	strLine = NewStringTable::strBondDealTips(2);
	strLine.append(" ");
	strLine.append(QString("%1").arg(dealInfo.m_count));
	strLine.append(" ").append(NewStringTable::strBondDealTips(3));
	m_strTips.append(strLine);
	item.clrNormal = crPrice;
	item.row = 3 + no;
	item.col = 1;
	item.font = nullptr;
	m_vctTipsCustomItem.push_back(item);
}

void BondDealMatrixBlockBase::paintEvent(QPaintEvent* event)
{
	if (!CBondContainer::instance().IsValidIndex(m_bondIndex))
		return;

	QStylePainter painter(this);

	bool bTextShow = m_parent ? m_parent->getTextShowType() : false;
	
	drawBack(painter);
	
	QFontMetrics fmTitle(m_lfTitle), fmPrice(m_lfPrice), fmDiff(m_lfDiff);
	int nameHeight = fmTitle.height();
	int priceHeight = 0, diffHeight = 0;
	if (bTextShow == 0) //收益率
	{
		priceHeight = fmPrice.height();
		diffHeight = fmDiff.height();
	}
	else
	{
		priceHeight = fmDiff.height();
		diffHeight = fmPrice.height();
	}

	QRect rcClient = rect();
	int gap = (rcClient.height() - nameHeight - priceHeight - diffHeight) / 6;
	QRect rcTitle = rcClient;
	rcTitle.setBottom(rcTitle.top() + gap * 2 + nameHeight);

	QRect rcPrice, rcDiff;
	if (bTextShow == 0) //收益率
	{
		rcPrice = rcTitle;
		rcPrice.moveTo(rcPrice.left(), rcPrice.bottom());
		rcPrice.setBottom(rcPrice.top() + gap * 2 + priceHeight);
		rcDiff = rcPrice;
		rcDiff.moveTo(rcDiff.left(), rcDiff.bottom());
		rcDiff.setBottom(rcClient.bottom());
	}
	else
	{
		rcDiff = rcTitle;
		rcDiff.moveTo(rcDiff.left(), rcDiff.bottom());
		rcDiff.setBottom(rcDiff.top() + gap * 2 + diffHeight);
		rcPrice = rcDiff;
		rcPrice.moveTo(rcPrice.left(), rcPrice.bottom());
		rcPrice.setBottom(rcClient.bottom());
	}

	QColor crTitle = StyleMgr::instance().color("TextNormal");
	QPen penTitle(crTitle);
	painter.setPen(penTitle);
	painter.setFont(m_lfTitle);
	painter.drawText(rcTitle, m_strTitle, QTextOption(Qt::AlignCenter));

	QColor crPrice = StyleMgr::instance().color("Highlight");
	if (CHECK_DOUBLE_VALID(m_gapBP))
	{
		if (m_gapBP < -DOUBLE_ZERO)
			crPrice = StyleMgr::instance().color("Up_Increase_H1");
		else if (m_gapBP > DOUBLE_ZERO)
			crPrice = StyleMgr::instance().color("Down_Reduce_H1");
	}
	QPen penPrice(crPrice);
	painter.setPen(penPrice);
	if (bTextShow == 0) //收益率
	{
		painter.setFont(m_lfPrice);
		painter.drawText(rcPrice, m_strPrice, QTextOption(Qt::AlignCenter));

		painter.setFont(m_lfDiff);
		painter.drawText(rcDiff, m_strDiff, QTextOption(Qt::AlignCenter));
	}
	else
	{
		painter.setFont(m_lfPrice);
		painter.drawText(rcDiff, m_strDiff, QTextOption(Qt::AlignCenter));

		painter.setFont(m_lfDiff);
		painter.drawText(rcPrice, m_strPrice, QTextOption(Qt::AlignCenter));
	}
}

int getGapLevel(double fGap, const double* pLevel)
{
	for (int i = levelCount - 1; i > 0; i--)
	{
		if (fGap - pLevel[i] > 1e-5)return i;
	}
	return 0;
}

void BondDealMatrixBlockBase::drawBack(QStylePainter& painter)
{
	QRect r = rect();
	int fillMode = m_parent ? m_parent->getChartShowType() : eModeBlock;
	QColor crBack = crNormal;
	bool validGap = CHECK_DOUBLE_VALID(m_gapBP);

	switch (fillMode)
	{
		case eModeBlock:
		{
			if (validGap)
			{
				double fGapAbs = fabs(m_gapBP);
				int level = 0;
				const CBondInfo& bi = CBondContainer::instance().ElementAtR(m_bondIndex);
				if (bi.is_interest_bond())
				{
					level = getGapLevel(fGapAbs, levelIntrest);
				}
				else if (bi.is_credit_bond())
				{
					level = getGapLevel(fGapAbs, levelCredit);
				}
				else if (bi.IsBondNCD())
				{
					level = getGapLevel(fGapAbs, levelNCD);
				}

				if (m_gapBP > DOUBLE_ZERO)
				{
					crBack = crGreen[level];
				}
				else if (m_gapBP < -DOUBLE_ZERO)
				{
					crBack = crRed[level];
				}
			}
			painter.fillRect(r, crBack);
			break;
		}
		case eModeHorz:
		{
			if (validGap)
			{
				double fGapAbs = fabs(m_gapBP);
				int level = 0;
				const CBondInfo& bi = CBondContainer::instance().ElementAtR(m_bondIndex);
				float fBpFull;

				if (bi.is_interest_bond())
				{
					fBpFull = 5.0;
					level = getGapLevel(fGapAbs, levelIntrest);
				}
				else if (bi.is_credit_bond())
				{
					fBpFull = 100;
					level = getGapLevel(fGapAbs, levelCredit);
				}
				else if (bi.IsBondNCD())
				{
					fBpFull = 10;
					level = getGapLevel(fGapAbs, levelNCD);
				}
				if (fGapAbs < fBpFull) {
					int rValue = r.left() + r.width() / fBpFull * fGapAbs;
					r.setRight(rValue);
				}

				if (m_gapBP > DOUBLE_ZERO)
				{
					crBack = crGreen[level];
				}
				else if (m_gapBP < -DOUBLE_ZERO)
				{
					crBack = crRed[level];
				}
			}
			painter.fillRect(r, crBack);
			break;
		}
		case eModeVert:
		{
			if (validGap)
			{
				double fGapAbs = fabs(m_gapBP);
				int level = 0;
				const CBondInfo& bi = CBondContainer::instance().ElementAtR(m_bondIndex);
				float fBpFull;

				if (bi.is_interest_bond())
				{
					fBpFull = 5.0;
					level = getGapLevel(fGapAbs, levelIntrest);
				}
				else if (bi.is_credit_bond())
				{
					fBpFull = 100;
					level = getGapLevel(fGapAbs, levelCredit);
				}
				else if (bi.IsBondNCD())
				{
					fBpFull = 10;
					level = getGapLevel(fGapAbs, levelNCD);
				}
				//bp上涨部分
				if (m_gapBP > DOUBLE_ZERO)
				{
					crBack = crGreen[level];
					if (fGapAbs < fBpFull) {
						r.setBottom(r.bottom() - r.height() / 2);
						r.setTop(r.bottom() - r.height() / (2 * fBpFull) * fGapAbs);
					}
					else
					{
						r.setBottom(r.bottom() - r.height() / 2);
						r.setTop(r.bottom() - r.height() / 2);
					}
				}
				else
				{
					//bp下跌部分
					crBack = crRed[level];
					if (fGapAbs < fBpFull) {
						r.setTop(r.bottom() - r.height() / 2);
						r.setBottom(r.top() + r.height() / (2 * fBpFull) * fGapAbs);
					}
					else {
						r.setTop(r.bottom() - r.height() / 2);
						r.setBottom(r.top() + r.height() / 2);
					}
				}
			}
			painter.fillRect(r, crBack);
			break;
		}
		default:
			break;
	}
	if (m_flashPos > 0)
	{
		int scale = m_flashPos * 255 / flashPosMax;
		QColor crTemp = QColor::fromRgb(crCover.red(), crCover.green(), crCover.blue(), scale);
		painter.fillRect(rect(), crTemp);
	}
}

void BondDealMatrixBlockBase::mouseMoveEvent(QMouseEvent* event)
{
	QPoint pt = event->screenPos().toPoint();
	qb::QBTips::showText(pt, m_strTips, this, &m_vctTipsCustomItem, true);
}

void BondDealMatrixBlockBase::mouseDoubleClickEvent(QMouseEvent* event)
{
	if (m_bondIndex == -1) return;
	const CBondInfo& bi = CBondContainer::instance().ElementAtR(m_bondIndex);
	CmdInfo ci(CMD_BondDetail, 0, bi.GetCombBondKey(), nullptr);
	QbBondModule::instance().app()->execCommand(CMD_BondDetail, bi.GetCombBondKey());
}

void BondDealMatrixBlockBase::onTimeOut()
{
	if (m_flashPos <= 0)
	{
		m_flashPos = 0;
		m_flashTimer->stop();
		return;
	}
	m_flashPos--;
	repaint();
}